package jlfm.lastfm.apps.recorder;

import java.io.IOException;
import java.io.InputStream;

import jlfm.lastfm.client.TrackMetadata;
import jlfm.lastfm.client.impl.simple.StreamHandler;
import jlfm.lastfm.client.impl.stream.StreamHandlingException;

public abstract class AbstractStatusReportingStreamHandler implements
		StreamHandler {

	private SequentialProgressListener informer = new SequentialProgressListener();

	int bytesRead = 0;

	public boolean handleStream(final TrackMetadata metadata,
			final InputStream in) throws StreamHandlingException {
		bytesRead = 0;

		informer.progressStarted(new ProgressEvent(this, metadata, bytesRead));

		boolean ret = handleStreamIntern(metadata, new InternalInStream(in,
				metadata));

		informer.progressFinished(new ProgressEvent(this, metadata, bytesRead));

		return ret;
	}

	public void addProgressListener(ProgressListener pl) {
		informer.addProgressListener(pl);
	}

	public boolean removeProgressListener(ProgressListener pl) {
		return informer.removeProgressListener(pl);
	}

	public abstract boolean handleStreamIntern(TrackMetadata metadata,
			InputStream in);

	class InternalInStream extends InputStream {
		private InputStream in;

		private TrackMetadata metadata;

		public InternalInStream(InputStream in, TrackMetadata metadata) {
			this.in = in;
			this.metadata = metadata;
		}

		@Override
		public int available() throws IOException {
			return in.available();
		}

		@Override
		public void close() throws IOException {
			in.close();
		}

		@Override
		public synchronized void mark(int readlimit) {
			in.mark(readlimit);
		}

		@Override
		public boolean markSupported() {
			return false;
		}

		@Override
		public int read() throws IOException {
			int r = in.read();
			if (r > 0) {
				bytesRead++;
			}
			informer.progressUpdated(new ProgressEvent(
					AbstractStatusReportingStreamHandler.this, metadata,
					bytesRead));
			return r;
		}

		@Override
		public int read(byte[] b, int off, int len) throws IOException {
			int r = in.read(b, off, len);
			if (r > 0) {
				bytesRead += r;
			}
			informer.progressUpdated(new ProgressEvent(
					AbstractStatusReportingStreamHandler.this, metadata,
					bytesRead));
			return r;
		}

		@Override
		public int read(byte[] b) throws IOException {
			int r = in.read(b);
			if (r > 0) {
				bytesRead += r;
			}
			informer.progressUpdated(new ProgressEvent(
					AbstractStatusReportingStreamHandler.this, metadata,
					bytesRead));
			return r;
		}

		@Override
		public synchronized void reset() throws IOException {
			in.reset();
		}

		@Override
		public long skip(long n) throws IOException {
			long r = in.skip(n);
			if (r > 0) {
				bytesRead += r;
			}
			informer.progressUpdated(new ProgressEvent(
					AbstractStatusReportingStreamHandler.this, metadata,
					bytesRead));
			return r;
		}

	}

}
